package main

import (
	"crypto/md5"
	"fmt"
	"math/rand"
	"sort"
	"sync"
	"time"
)

type Pod struct {
	Name        string
	data        map[string]interface{}
	create_time int64
	locker      sync.RWMutex
}

func NewPod(s string) *Pod {
	a := new(Pod)
	a.Name = s
	a.locker = sync.RWMutex{}
	a.data = make(map[string]interface{}, 7)
	return a
}

func (p *Pod) AddLabel(k string, v interface{}) {
	p.locker.Lock()
	p.data[k] = v
	p.locker.Unlock()
}

type Deployment struct {
	Name   string
	Pods   []*Pod
	locker sync.RWMutex
}

func NewDep(num int, name string) *Deployment {

	dp := new(Deployment)
	dp.Name = name
	dp.Pods = make([]*Pod, num+1)
	return dp
}
func (d *Deployment) AddPod(p *Pod) bool {
	for k, v := range d.Pods {
		if v == nil {
			d.locker.Lock()
			d.Pods[k] = p
			d.Pods[k].AddLabel("create_time", time.Now().Unix())
			d.Pods[k].create_time = time.Now().Unix()
			d.locker.Unlock()
			fmt.Println("deployment ", d.Name, " add pod ", p.Name, " succeed")
			return true
		}
	}
	fmt.Println("deployment ", d.Name, " add pod ", p.Name, " faild no space left on deployment ", d.Name)
	return false
}

func (d *Deployment) DelPod(podname string) bool {
	for k, v := range d.Pods {
		if v.Name == podname {
			//delete(d.Pods[k]) //居然无法释放空间
			d.locker.Lock()
			d.Pods[k] = nil
			d.locker.Unlock()
			fmt.Println("pod ", podname, " deleted")
			return true
		}
	}
	fmt.Println("delete faild no pod named ", podname, "found")
	return false
}
func (d *Deployment) Update(p *Pod) bool {
	if d.AddPod(p) {
		return true
	} else {
		d.locker.Lock()
		d.Pods = append(d.Pods, p)
		d.Pods[len(d.Pods)-1].data["create_time"] = time.Now().Unix()
		d.Pods[len(d.Pods)-1].create_time = time.Now().Unix()
		d.locker.Unlock()
		fmt.Printf("deployment %s extend\n", d.Name)
		return true
	}
}
func (d *Deployment) ListPods() {
	for k, v := range d.Pods {
		if v == nil {
			break
		} else {
			fmt.Println(d.Pods[k].Name, d.Pods[k].data)
		}
	}
}
func (d *Deployment) Len() int { return len(d.Pods) }
func (d *Deployment) Less(x, y int) bool {
	if (d.Pods[x] != nil) && (d.Pods[y] != nil) {
		return d.Pods[x].create_time < d.Pods[y].create_time
	} else if d.Pods[x] == nil {
		return false
	} else {
		return true
	}
}
func (d *Deployment) Swap(x, y int) {
	d.locker.Lock()
	d.Pods[x], d.Pods[y] = d.Pods[y], d.Pods[x]
	d.locker.Unlock()
}
func (d *Deployment) DelOldPod() {

	sort.Sort(d)
	d.locker.Lock()
	d.Pods[0] = nil
	d.locker.Unlock()
	sort.Sort(d)

	return
}

const num int = 2

func main() {
	var rand1 string
	rand.Seed(time.Now().Unix())
	dp := NewDep(num, "deployment1") //初始化一个deployment
	for {
		time.Sleep(1 * time.Second)
		rand1 = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintln(rand.Int()))))
		if !dp.AddPod(NewPod(rand1)) {
			break
		}
	}
	dp.Update(NewPod(rand1))
	dp.ListPods()
	fmt.Println(dp.Pods)
	dp.DelOldPod()
	fmt.Println(dp.Pods)
	dp.ListPods()
	time.Sleep(1 * time.Second)
	dp.Update(NewPod(rand1))
	dp.Update(NewPod(rand1))
	fmt.Println(dp.Pods)
	dp.ListPods()

}
